package cn.ciis.basic.kit;

import cn.ciis.basic.base.BaseCache;
import cn.ciis.basic.model.Dictionary;
import cn.ciis.basic.model.Enterprise;
import cn.ciis.basic.model.Equipment;
import cn.ciis.basic.plugin.CiisPlugs;
import cn.ciis.basic.plugin.CiisSessionContext;
import cn.ciis.ciis.dictionary.DictionaryAdminService;
import cn.ciis.server.CiisPacket;
import cn.hutool.core.util.StrUtil;
import com.jfinal.aop.Aop;
import com.jfinal.kit.*;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author 冉志林
 */
public class CiisKit {

    public static final String RN = "\r\n";//可替换Common.RN

    public static String RESOURCE_VERSION=null;

    private static DictionaryAdminService dictionaryAdminService = Aop.get(DictionaryAdminService.class);

    /**
     * 项目根目录
     *
     * @return
     */
    public static String getWebRoot() {
        return System.getProperty("user.dir");
    }

    /*获取导入的配置文件*/
    public static Prop getImportProperties() {
        return PropKit.use("config/import.setting", "UTF-8");
    }


    public static String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 下划线转驼峰
     *
     * @param param
     * @return
     */
    public static String underlineToCamel(String param) {
        char UNDERLINE = '_';
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = Character.toLowerCase(param.charAt(i));
            if (c == UNDERLINE) {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 首字母大写
     *
     * @param letter
     * @return
     */
    public static String upperFirstLatter(String letter) {
        char[] chars = letter.toCharArray();
        if (chars[0] >= 'a' && chars[0] <= 'z') {
            chars[0] = (char) (chars[0] - 32);
        }
        return new String(chars);
    }




    /**
     * 将字符串计算表达式转换为表达式并计算值
     *
     * @param str
     * @return
     */
    public static Object strToMath(String str) {
        Object result = null;
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");
        try {
            result = engine.eval(str);
        } catch (ScriptException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 消息发送
     * @param channelContext t-io会话信息
     * @param ciisPacket 发送的消息体
     */
    public static boolean sendMsg(ChannelContext channelContext, CiisPacket ciisPacket) {

        return Tio.send(channelContext, ciisPacket);
    }

    /**
     * 根据bsid发送消息
     * @param bsId
     * @param ciisPacket
     * @return
     */
    public static boolean sendMsg(String bsId, CiisPacket ciisPacket) {
        return Tio.sendToBsId(CiisPlugs.ciisServerTioConfig,bsId,ciisPacket);
    }

    /**
     * 通过Tio会话session发送消息
     * @param sessionContext
     * @param ciisPacket
     * @return
     */
    public static boolean sendMsg(CiisSessionContext sessionContext,CiisPacket ciisPacket){
        String bsId = getBsIdForCiisSessionContext(sessionContext);

        if(StrKit.notBlank(bsId)){
            return Tio.sendToBsId(CiisPlugs.ciisServerTioConfig, bsId, ciisPacket);
        }else{
            return false;
        }

    }

    /**
     * 通过Tio会话获取BsId
     * @param sessionContext
     * @return
     */
    public static String getBsIdForCiisSessionContext(CiisSessionContext sessionContext){
        if(sessionContext.getEquipment().isPresent() && sessionContext.getEnterprise().isPresent()){
            return getTioBsId(sessionContext.getEnterprise().get(), sessionContext.getEquipment().get());
        }else{
            return null;
        }
    }

    /**
     * 通过设备发送消息
     * @param equipment
     * @param ciisPacket
     * @return
     */
    public static Boolean sendMsg(Equipment equipment,CiisPacket ciisPacket){
        String str=getTioBsId(equipment.getEnterprise(),equipment);
        return Tio.sendToBsId(CiisPlugs.ciisServerTioConfig,str,ciisPacket);
    }

    /**
     * 查找某一文件中是否包含有指定字符串
     *
     * @param path
     * @param str
     * @return
     * @throws IOException
     */
    public static boolean findStringInFile(String path, String str) throws IOException {
        File file = new File(path);
        InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8");//考虑到编码格式
        @SuppressWarnings("resource")
        BufferedReader bufferedReader = new BufferedReader(read);
        String line = null;
        while ((line = bufferedReader.readLine()) != null) {
            //指定字符串判断处
            if (line.contains(str)) {
                return true;
            }
        }
        return false;
    }



    /**
     * 替换中括号为空
     *
     * @param str
     * @return
     */
    public static String replaceBrackets(String str) {
        String replace = str.replace("[", "").replace("]", "");
        return replace;
    }


    /**
     * 递归删除所有的子节点
     *
     * @param k
     * @return
     */
    public static Map<Integer, Integer> removeTreeNodes(Integer k, String tableName) {

        Map<Integer, Integer> t = new HashMap<Integer, Integer>();
        String sql = "select * from " + tableName;
        List<Record> list = Db.find(sql);
        for (Record record : list) {
            t.put(record.get("id"), record.get("pId"));
        }

        //所有需要删除的子节点
        List<Integer> sons = new ArrayList<Integer>();
        sons.add(k);
        List<Integer> temp = new ArrayList<Integer>();
        //循环递归删除，所有以k位父节点的节点
        while (true) {
            for (Integer s : sons) {
                Set<Integer> keys = t.keySet();
                Iterator<Integer> it = keys.iterator();
                while (it.hasNext()) {
                    Integer n = it.next();
                    //如果父节点(即Map的value)为需要删除的节点，则记录此几点，并在Map中删除
                    if (t.get(n) == s) {
                        temp.add(n);
                        it.remove();
                        Db.delete("delete from " + tableName + " where id=" + n);
                    }
                }
            }
            if (temp.size() > 0) {
                sons = temp;
                temp = new CopyOnWriteArrayList<Integer>();
            } else {
                break;
            }
        }
        Db.delete("delete from " + tableName + " where id=" + k);
        return t;
    }



    /**
     * @Title: findParagraph
     * @Description: 根据查找字符串划分内容（第一个符合的字符串对象有效）
     * @param @param filePath 文件路径
     * @param @param context 查找的字符串
     * @param @return List<String>
     * @param @throws IOException
     * @return List<String>
     * @throws
     */
    public static List<String> findParagraph(String filePath, String context) throws IOException {
        BufferedReader read = new BufferedReader(new FileReader(filePath));
        List<String> list = new LinkedList<String>();
        String paragraphHead = "";
        String paragraphEnd = "";
        String line = "";
        int index = 0;
        int lineNum=1;
        while ((line = read.readLine()) != null) {
            if (index == 0) {
                paragraphHead += (line + RN);
            }
            if (line.indexOf(context) != -1 && index == 0) {
                LogKit.info("行号："+lineNum+"，当前行内容: "+line);
                list.add(paragraphHead);
                index++;
                continue;
            }
            if (index > 0) {
                paragraphEnd += (line + RN);
            }
            lineNum++;
        }
        list.add(paragraphEnd);
        read.close();
        return list;
    }


    /**
     * @Title: writeParagraph
     * @Description:
     * @param @param filePath 路径
     * @param @param context 要查找的字符串
     * @param @param wcontext要写入的内容
     * @param @param codeType 编码格式（默认utf-8）
     * @param @throws IOException
     * @return void
     * @throws
     */
    public static void writeParagraph(String filePath, String context, String wcontext, String codeType) throws IOException {
        File fileName = new File(filePath);
        List<String> list = findParagraph(filePath, context);
        RandomAccessFile randomFile = null;
        OutputStreamWriter write = null;
        if (codeType != null && !codeType.trim().equals("")) {
            write = new OutputStreamWriter(new FileOutputStream(fileName), codeType);
        } else {
            write = new OutputStreamWriter(new FileOutputStream(fileName), "utf-8");
        }
        //清空文件内容
        write.write("");
        write.close();
        try {
            // 打开一个随机访问文件流，按读写方式
            randomFile = new RandomAccessFile(fileName, "rw");
            int index=0;
            for (int i = 0; i < list.size(); i++) {
                if (index==0) {
                    randomFile.write(list.get(i).getBytes());
                    randomFile.write((wcontext + RN).getBytes());
                }
                if (index>0) {
                    randomFile.write(list.get(i).getBytes());
                }
                index++;
            }
            LogKit.info("操作完成！");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (randomFile != null) {
                try {
                    randomFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 传入企业信息和设备信息获取绑定到tio会话的业务id
     * @param enterprise
     * @param equipment
     * @return
     */
    public static String getTioBsId(Enterprise enterprise, Equipment equipment){

        if(enterprise == null || equipment == null){
            return "";
        }else{
            return StrUtil.format("{}-{}-{}", enterprise.getCode()
                    , equipment.getCode()
                    , equipment.getPort());
        }
    }
    public static Ret getTioBsId(String bsid){
        String[] split = bsid.split("-");
        Ret ret=Ret.create();
        ret.set("enterpriseCode",split[0]);
        ret.set("equipmentCode",split[1]);
        return ret;
    }



    /**
     * 从Tio会话中获取传感器、阀门在线状态
     * @param equipment
     * @return
     */
    public static void refreshByTio(Equipment equipment){

        if(equipment.isConnect()){
            String bsId = getTioBsId(equipment.getEnterprise(), equipment);
            ChannelContext channelContext = Tio.getByBsId(CiisPlugs.ciisServerTioConfig, bsId);

            if(channelContext == null){
                return;
            }

            CiisSessionContext ciisSessionContext = (CiisSessionContext) channelContext.get("ciisSessionContext");

            if(ciisSessionContext.getEquipment().isPresent()){

                equipment.setSensorStr(ciisSessionContext.getEquipment().get().getSensorStr());//从会话中获取传感器在线状态
                equipment.setValveStr(ciisSessionContext.getEquipment().get().getValveStr());//从会话中获取阀门开关状态
                //传感器类型缓存
                List<Dictionary> dictionary= (List<Dictionary>) J2CacheKit.get(BaseCache.EQUIPMENT_DATA_DICTIONARY,"01", s -> {
                    return  dictionaryAdminService.findByPid(1);
                }).getValue();

                //从Tio会话中获取传感器数据
                if(ciisSessionContext.getEquipment().get().get("now_data") !=null){
                    Map<String,Object> sensor = ciisSessionContext.getEquipment().get().get("now_data");
                    sensor.keySet().forEach(key->{
                        Optional<Dictionary> dictionaryOptional = dictionary.stream().filter(dic -> {
                            return dic.getField().equals(key);
                        }).findFirst();

                        if(dictionaryOptional.isPresent()){
                            sensor.put(dictionaryOptional.get().getName(), sensor.get(key));
                        }
                    });
                    equipment.put("now_data", sensor);
                }
            }
        }
    }

}
